package com.ruoyi.eqmonitor.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.eqmonitor.dispose.domain.OpentsdbTags;
import com.ruoyi.eqmonitor.domain.OptDeviceMonitorConfig;
import com.ruoyi.eqmonitor.domain.OptDeviceMonitorMonth;
import com.ruoyi.eqmonitor.domain.SnCodeRelation;
import com.ruoyi.eqmonitor.dtos.WaterConditionParticularExport;
import com.ruoyi.eqmonitor.domain.OptDeviceMonitorLastData;
import com.ruoyi.eqmonitor.dtos.*;
import com.ruoyi.eqmonitor.exception.OpentsdbException;
import com.ruoyi.eqmonitor.mapper.OptDeviceMapper;
import com.ruoyi.eqmonitor.mapper.OptDeviceMonitorLastDataMapper;
import com.ruoyi.eqmonitor.mapper.PipeMapper;
import com.ruoyi.eqmonitor.service.*;
import com.ruoyi.eqmonitor.utils.Constant;
import com.ruoyi.eqmonitor.utils.OpenTSDBUtils;
import com.ruoyi.eqmonitor.vo.CockpitVo;
import com.ruoyi.eqmonitor.vo.OptDeviceMonitorLastDataVo;
import lombok.extern.slf4j.Slf4j;
import org.opentsdb.client.bean.request.SubQuery;
import org.opentsdb.client.bean.response.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 设备监测最新实时数据Service业务层处理
 *
 * @author ruoyi
 * @date 2022-11-25
 */
@Slf4j
@Service
public class OptDeviceMonitorLastDataServiceImpl extends ServiceImpl<OptDeviceMonitorLastDataMapper, OptDeviceMonitorLastData> implements IOptDeviceMonitorLastDataService {

    @Resource
    private OpenTSDBUtils openTSDBUtils;
    @Resource
    private IOptDeviceService iOptDeviceService;
    @Resource
    private OptDeviceMapper optDeviceMapper;
    @Resource
    private IOptDeviceMonitorMonthService optDeviceMonitorMonthService;
    @Autowired
    private IOptDeviceMonitorConfigService optDeviceMonitorConfigService;
    @Resource
    private PipeMapper pipeMapper;

    @Override
    public OptDeviceMonitorLastData selectOptDeviceMonitorLastDataById(Long id) {
        String tableName = pipeMapper.getTableNameByCode("WSGSZ_POINT").toUpperCase(Locale.ROOT);
        return baseMapper.selectOptDeviceMonitorLastDataById(id, tableName);
    }

    @Override
    public List<OptDeviceMonitorLastData> selectOptDeviceMonitorLastDataList(OptDeviceMonitorLastData optDeviceMonitorLastData) {
        String tableName = pipeMapper.getTableNameByCode("WSGSZ_POINT").toUpperCase(Locale.ROOT);
        optDeviceMonitorLastData.setWsgPointTableName(tableName);
        return baseMapper.selectOptDeviceMonitorLastDataList(optDeviceMonitorLastData);
    }

    /**
     * 批量新增或更新监测数据
     *
     * @param listData 列表数据
     * @return 是否批量执行成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateMonitorLastData(Collection<OptDeviceMonitorLastData> listData) {
        baseMapper.saveOrUpdateMonitorLastData(listData);
    }

    @Override
    public List<Map<String, Object>> selectFlow() throws OpentsdbException, ParseException {
        // 查询泵站周边的流量监测仪
        List<OptDeviceDto> deviceDtos = iOptDeviceService.getBzFlowDevice();
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        List<QueryResult> queryResults = new ArrayList<>();
        /*//查询数据
        List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(null, null,
                    "1hc-avg-zero",
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0592.getCode());*/

        //处理数据
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh");
        DecimalFormat df = new DecimalFormat("#.000");

        List<Map<String, Object>> list = new ArrayList<>();
        for (QueryResult queryResult : queryResults) {
            // 将tags的base64转换为原始的字符串
            OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
            Map<String, Object> map = new HashMap<>();
            map.put("tags", opentsdbTags);

            //处理时间和数据
            List<String> time = new ArrayList<>();
            List<String> value = new ArrayList<>();
            List<String> value2 = new ArrayList<>();
            double sumValue = 0.000;
            LinkedHashMap<Long, Number> dps = queryResult.getDps();
            for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                //时间戳
                Long key = entry.getKey();

                time.add(sdf.format(new Date(key * 1000L)));
                double v = entry.getValue().doubleValue();
                value.add(df.format(v));
                sumValue += v;
                value2.add(df.format(sumValue));
            }
            map.put("time", time);
            map.put("value", value);
            map.put("value2", value2);

            // 加入设备信息
            String snCode = opentsdbTags.getSnCode();
            deviceDtos.stream()
                    .filter(dto -> dto.getDeviceCode().equals(snCode))
                    .findFirst()
                    .ifPresent(device -> {
                        map.put("device", device);
                        map.put("deviceName", device.getSiteName());
                        map.put("sumDeviceName", device.getSiteName());
                    });

            list.add(map);
        }

        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map<String, Object> originalMap : list) {
            OpentsdbTags tags = (OpentsdbTags) originalMap.get("tags");

            Map<String, Object> map1 = new HashMap<>();
            map1.put("tags", tags);
            map1.put("time", originalMap.get("time"));
            map1.put("value", originalMap.get("value"));
            map1.put("device", originalMap.get("device"));
            map1.put("deviceName", originalMap.get("deviceName"));

            Map<String, Object> map2 = new HashMap<>();
            tags.setMonitorName("正向累计流量");
            map2.put("tags", tags);
            map2.put("time", originalMap.get("time"));
            map2.put("value", originalMap.get("value2"));
            map2.put("device", originalMap.get("device"));
            map2.put("deviceName", originalMap.get("sumDeviceName"));

            resultList.add(map1);
            resultList.add(map2);
        }
        return resultList;
    }

    //管道流量监测仪流量+液位
    @Override
    public List<Map<String, Object>> selectGuandao() throws ParseException, OpentsdbException {
        // 查询设备
        OptDeviceDto optDeviceDto = new OptDeviceDto();
        optDeviceDto.setDeviceType(Constant.EquipmentType.SR500_L_Y0_LD.getCode());
        List<OptDeviceDto> deviceDtos = iOptDeviceService.selectOptDeviceList(optDeviceDto);
        if (deviceDtos.size() == 0) {
            return null;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(null, null,
                    "1hc-avg",
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0592.getCode());*/

        //数据处理
        List<Map<String, Object>> list = this.DisposeData(queryResults, null, false, false, deviceDtos);
        for (Map<String, Object> map : list) {
            JSONObject json = new JSONObject(map);
            String time = String.valueOf(json.get("time"));
            String[] timeSplit = time.split(",");
            String stringTime = timeSplit[timeSplit.length - 1];
            map.put("time", stringTime.substring(1, stringTime.length() - 1));
            String value = String.valueOf(json.get("value"));
            String[] valueSplit = value.split(",");
            String stringValue = valueSplit[valueSplit.length - 1];
            map.put("value", stringValue.substring(1, stringValue.length() - 1));
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> selectAnDanLiuLiangNYR(String datetime, Integer state) throws ParseException, IllegalAccessException, OpentsdbException {
        //处理参数
        Calendar c = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        if (state == 2) {
            Date parse = sdf.parse(datetime);
            c.setTime(parse);
            c.add(Calendar.DAY_OF_MONTH, 1);
        } else if (state == 1) {
            datetime = datetime + "-01";
            Date parse = sdf.parse(datetime);
            c.setTime(parse);
            c.add(Calendar.MONTH, 1);
        } else if (state == 0) {
            datetime = datetime + "-01-01";
            Date parse = sdf.parse(datetime);
            c.setTime(parse);
            c.add(Calendar.YEAR, 1);
        }

        // 查询设备
        OptDeviceDto optDeviceDto = new OptDeviceDto();
        //optDeviceDto.setDeviceType(Constant.EquipmentType.SR500_L_Y0_LDN.getCode());
        List<OptDeviceDto> deviceDtos = iOptDeviceService.selectOptDeviceList(optDeviceDto);
        if (deviceDtos.size() == 0) {
            return null;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        //设置降精度方式
        SimpleDateFormat sdf2 = null;
        String downsample = null;
        switch (state) {
            case 0:
                sdf2 = new SimpleDateFormat("yyyy");
                downsample = "1y-avg-zero";
                break;
            case 1:
                sdf2 = new SimpleDateFormat("yyyy-MM");
                downsample = "1m-avg-zero";
                break;
            case 2:
                sdf2 = new SimpleDateFormat("yyyy-MM-dd");
                downsample = "1d-avg-zero";
                break;
            default:
                throw new IllegalAccessException("state参数错误");
        }
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(sdf.parse(datetime).getTime(), c.getTime().getTime(),
                    downsample,
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0528.getCode(),
                    Constant.MonitorInfo.M_0x0592.getCode(),
                    Constant.MonitorInfo.M_0x05D1.getCode());*/

        //数据处理并返回
        return this.DisposeData(queryResults, sdf2, false, false, deviceDtos);
    }

    @Override
    public List<Map<String, Object>> selectAnDanShuiZhi(String deviceName, Integer state) throws ParseException, OpentsdbException {
        // 查询设备
        OptDeviceDto dto = new OptDeviceDto();
        dto.setDeviceName(deviceName);
        List<OptDeviceDto> deviceDtos = iOptDeviceService.getByDeviceTypes(dto);
        if (deviceDtos.size() == 0) {
            return null;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);

        //查询数据,处理并返回
        List<QueryResult> queryResults = null;
        SimpleDateFormat sdf = null;
        if (state != null && state == 2) {
            //近一个月数
            Date date = new Date();
            Long beginTime = DateUtils.getLastMonth(date).getTime();
            /*queryResults = openTSDBUtils.TSDBQuery(beginTime, date.getTime(),
                    "1h-avg",
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0523.getCode(),
                    Constant.MonitorInfo.M_0x0527.getCode(),
                    Constant.MonitorInfo.M_0x0528.getCode());*/
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        } else {
            //实时数据
           /* queryResults = openTSDBUtils.TSDBQuery(null, null,
                    "1hc-avg-zero",
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0523.getCode(),
                    Constant.MonitorInfo.M_0x0527.getCode(),
                    Constant.MonitorInfo.M_0x0528.getCode());*/
        }
        return this.DisposeData(queryResults, sdf, false, false, deviceDtos);
    }

    @Override
    public List<Map<String, Object>> selectRiverwayMonitor(RiverwayMonitorDto dto) throws ParseException, IllegalAccessException, OpentsdbException {
        //处理时间参数
        this.disposeDate(dto);

        // 查询设备
        Integer state = dto.getState();
        List<OptDeviceDto> deviceDtos = iOptDeviceService.getByDeviceType(state, dto.getSearchValues());
        if (deviceDtos.size() == 0) {
            return null;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        // 创建monitorCode过滤器 过滤监测数据
        SubQuery.Filter monitorCodeFilter = null;
        switch (state) {
            case 0:
                monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(Constant.MonitorInfo.M_0x05D1.getCode());
                break;
            case 1:
                monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(Constant.MonitorInfo.M_0x0592.getCode());
                break;
            case 2:
                monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(
                        Constant.MonitorInfo.M_0x0520.getCode(),
                        Constant.MonitorInfo.M_0x0523.getCode(),
                        Constant.MonitorInfo.M_0x0527.getCode(),
                        Constant.MonitorInfo.M_0x0528.getCode());
                break;
            case 3:
                //24小时降雨量
                monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(Constant.MonitorInfo.M_0x0566.getCode());
                break;
            default:
                throw new IllegalAccessException("state参数错误");
        }
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
       /* List<QueryResult> queryResults = openTSDBUtils.TSDBQuery2(dto.getBeginTime(), dto.getEndTime(),
                "1hc-avg-zero",
                deviceCodes,
                monitorCodeFilter);*/

        //数据处理
        return this.DisposeData(queryResults, null, false, false, deviceDtos);
    }

    @Override
    public List<RiverwayMonitorExport> selectRiverwayMonitorExport(RiverwayMonitorDto dto) throws ParseException, OpentsdbException {
        //处理时间参数
        this.disposeDate(dto);

        // 查询设备
        Integer state = dto.getState();
        List<OptDeviceDto> deviceDtos = iOptDeviceService.getByDeviceType(state, dto.getSearchValues());
        if (deviceDtos.size() == 0) {
            return null;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        // 创建monitorCode过滤器 过滤监测数据
        SubQuery.Filter monitorCodeFilter = null;
        if (state == 0) {
            monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(Constant.MonitorInfo.M_0x05D1.getCode());
        } else if (state == 1) {
            monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(Constant.MonitorInfo.M_0x0592.getCode());
        } else {
            monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(
                    Constant.MonitorInfo.M_0x0520.getCode(),
                    Constant.MonitorInfo.M_0x0523.getCode(),
                    Constant.MonitorInfo.M_0x0527.getCode(),
                    Constant.MonitorInfo.M_0x0528.getCode());
        }
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery2(dto.getBeginTime(), dto.getEndTime(),
                "1hc-avg-zero",
                deviceCodes,
                monitorCodeFilter);*/

        //数据处理
        List<RiverwayMonitorExport> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:00");
        for (QueryResult queryResult : queryResults) {
            OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
            //获取设备信息
            OptDeviceDto device = iOptDeviceService.getDeviceByCode(opentsdbTags.getSnCode());

            LinkedHashMap<Long, Number> dps = queryResult.getDps();
            String timeFlag = null;//标记数据是否为同一个小时内
            Double valueFlag = 0.000;//累计数值
            int i = 0;//累计数值的个数
            for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                //格式化时间
                Long key = entry.getKey();
                Date dateTime = new Date(key * 1000L);
                String timeString = sdf.format(dateTime);
                Double v = entry.getValue().doubleValue();
                //第一次循环，赋值后跳过
                if (timeFlag == null) {
                    timeFlag = timeString;
                    valueFlag = v;
                    i = 1;
                    continue;
                }
                //时间与上一次相同，加入累计值后跳过
                if (timeString.equals(timeFlag)) {
                    valueFlag += v;
                    i++;
                    continue;
                }
                //加入时间和数值
                RiverwayMonitorExport export = createRiverwayMonitorExport(device, opentsdbTags, timeFlag, valueFlag, i);
                list.add(export);
                //重置循环标记
                timeFlag = timeString;
                valueFlag = v;
                i = 1;
            }
            //加入最后一条数据
            RiverwayMonitorExport export = createRiverwayMonitorExport(device, opentsdbTags, timeFlag, valueFlag, i);
            list.add(export);
        }
        return list;
    }

    private static RiverwayMonitorExport createRiverwayMonitorExport(OptDeviceDto device, OpentsdbTags opentsdbTags, String timeFlag, Double valueFlag, int count) {
        RiverwayMonitorExport export = new RiverwayMonitorExport();
        export.setSiteName(device.getSiteName());
        export.setDeviceName(device.getDeviceName());
        export.setAddress(device.getAddress());
        export.setAreaName(device.getAreaName());
        export.setMonitorName(opentsdbTags.getMonitorName());
        export.setDataUnit(opentsdbTags.getDataUnit());
        export.setTime(timeFlag);
        export.setValue(new BigDecimal(valueFlag).divide(BigDecimal.ONE, 3, BigDecimal.ROUND_HALF_UP));
        return export;
    }


    @Override
    public List<Map<String, Object>> selectWaterCondition(WaterQualityReportDto dto, SubQuery.Filter monitorCodeFilter) throws ParseException, OpentsdbException {
        //  创建snCodeFilter过滤器
        String[] codes = dto.getCodes().toArray(new String[dto.getCodes().size()]);

        Integer state = dto.getState();
        //处理时间并转为时间戳
        Date s = DateUtils.toDate(state, dto.getBeginTime(), dto.getBeginYear(), dto.getBeginDate(), false);
        Date s1 = DateUtils.toDate(state, dto.getEndTime(), dto.getEndYear(), dto.getEndDate(), true);
        Long beginTime = s.getTime();
        Long endTime = s1.getTime();

        //设置时间精度及聚合方式
        SimpleDateFormat sdf = null;
        String downsample = null;
        switch (state) {
            case 0:
                sdf = new SimpleDateFormat("yyyy");
                downsample = "1y-avg-zero";
                break;
            case 2:
                sdf = new SimpleDateFormat("yyyy-MM-dd");
                downsample = "1d-avg-zero";
                break;
            case 3:
                sdf = new SimpleDateFormat("yyyy-MM-dd");
                downsample = "7d-avg-zero";
                break;
            default:
                sdf = new SimpleDateFormat("yyyy-MM");
                downsample = "1M-avg-zero";
                break;
        }
        //查询数据
        List<QueryResult> queryResults = new ArrayList<>();
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery2(beginTime, endTime,
                    downsample,
                    codes,
                    monitorCodeFilter);*/

        //数据处理
        List<Map<String, Object>> maps = this.DisposeData(queryResults, sdf, true, false, null);
        if (state == 4 || state == 5) {
            //确定周期
            int interval = (state == 4) ? 4 : 6;
            maps.forEach(map -> {
                // 解析时间列表
                List<String> timeList = JSONArray.parseArray(JSONArray.toJSONString(map.get("time")), String.class);
                // 解析值列表
                List<String> valueList = JSONArray.parseArray(JSONArray.toJSONString(map.get("value")), String.class);
                // 计算新的时间列表
                List<String> newTimeList = IntStream.range(0, timeList.size())
                        .filter(i -> i % interval == 0) // 每隔 'interval' 个元素取一个
                        .mapToObj(timeList::get) // 将索引映射为对应的时间元素
                        .collect(Collectors.toList());
                // 计算新的值列表
                List<String> newValueList = IntStream.range(0, valueList.size())
                        .filter(i -> i % interval == 0) // 每隔 'interval' 个元素取一个
                        .mapToObj(i -> {
                            // 计算每个区间的和
                            BigDecimal sum = IntStream.range(i, Math.min(i + interval, valueList.size()))
                                    .mapToObj(valueList::get)
                                    .map(BigDecimal::new)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                            // 计算平均值并转换为字符串
                            return sum.divide(new BigDecimal(interval), BigDecimal.ROUND_HALF_UP).toString();
                        })
                        .collect(Collectors.toList());

                // 更新原始映射中的时间和值列表
                map.put("time", newTimeList);
                map.put("value", newValueList);
            });
        }
        return maps;
    }

    @Override
    public List<WaterConditionExport> selectWaterConditionExport(WaterQualityReportDto dto, SubQuery.Filter monitorCodeFilter) throws ParseException, OpentsdbException {
        List<WaterConditionExport> list = new ArrayList<>();
        //查询数据后做二次处理
        List<Map<String, Object>> maps = this.selectWaterCondition(dto, monitorCodeFilter);
        for (Map<String, Object> map : maps) {
            WaterConditionExport export = new WaterConditionExport();
            OptDeviceDto device = new ObjectMapper().convertValue(map.get("device"), OptDeviceDto.class);
            export.setSiteName(device.getSiteName());
            Map map1 = new ObjectMapper().convertValue(map.get("tags"), Map.class);
            export.setMonitorName(map1.get("monitorName").toString());
            List<String> timeList = new ObjectMapper().convertValue(map.get("time"), List.class);
            List<BigDecimal> valueList = new ObjectMapper().convertValue(map.get("value"), List.class);
            List<WaterConditionParticularExport> waterConditionParticularExports = new ArrayList<>();
            for (int i = 0; i < timeList.size(); i++) {
                WaterConditionParticularExport particularExport = new WaterConditionParticularExport();
                particularExport.setTime(timeList.get(i));
                if (valueList.size() > i) {
                    particularExport.setValue(valueList.get(i).toString());
                }
                waterConditionParticularExports.add(particularExport);
            }
            export.setList(waterConditionParticularExports);
            list.add(export);
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> selectWaterConditionAnalyse(WaterConditionAnalyseDto dto) throws ParseException, OpentsdbException {
        //处理时间
        Long beginTime = dto.getBeginTimeDate().getTime();
        Long endTime = DateUtils.getDayMax(dto.getEndTimeDate()).getTime();
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
       /* List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(beginTime, endTime,
                    "1hc-avg-zero",
                    dto.getCodes().toArray(new String[dto.getCodes().size()]),
                    Constant.MonitorInfo.M_0x0592.getCode(),
                    Constant.MonitorInfo.M_0x05D1.getCode());*/

        //数据处理
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH");
        return this.DisposeData(queryResults, sdf, true, false, null);
    }

    @Override
    public boolean selectRainfall(RiverwayMonitorDto dto) throws ParseException, OpentsdbException {
        // 查询设备
        Integer state = dto.getState();
        List<OptDeviceDto> deviceDtos = iOptDeviceService.getByDeviceType(state, dto.getSearchValues());
        if (deviceDtos.size() == 0) {
            return false;
        }
        // 过滤所有设备编码
        String[] deviceCodes = deviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(dto.getBeginTime(), dto.getEndTime(),
                    "1d-avg-zero",
                    deviceCodes,
                    Constant.MonitorInfo.C_CC0008.getCode());*/

        //数据处理
        boolean flag = false;//标记是否降水
        for (QueryResult queryResult : queryResults) {
            //判断降水量是否为0
            LinkedHashMap<Long, Number> dps = queryResult.getDps();
            for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                Double value = (Double) entry.getValue();
                if (value != 0) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

    @Override
    public List<Map<String, Object>> selectMonthCOD(String deviceCode) throws ParseException, OpentsdbException {
        String[] deviceCodes = {deviceCode};
        //处理时间
        Date dayMin = DateUtils.getDayMin(new Date());
        Long beginTime = DateUtils.getLastMonth(dayMin).getTime();
        Long endTime = dayMin.getTime();
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(beginTime, endTime,
                    "1d-avg-zero",
                    deviceCodes,
                    Constant.MonitorInfo.M_0x0528.getCode(),
                    Constant.MonitorInfo.M_0x0592.getCode(),
                    Constant.MonitorInfo.M_0x05D1.getCode());*/

        return this.DisposeData(queryResults, new SimpleDateFormat("yyyy-MM-dd"), false, false, null);
    }

    @Override
    public List<Map<String, Object>> selectWellLid(String siteId) throws ParseException, OpentsdbException {
        OptDeviceDto optDeviceDto = new OptDeviceDto();
        optDeviceDto.setSiteId(siteId);
        List<OptDeviceDto> optDeviceDtos = optDeviceMapper.selectOptDeviceList(optDeviceDto);
        if (optDeviceDtos.size() == 0) {
            return null;
        }
        String[] deviceCodes = optDeviceDtos.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
        List<QueryResult> queryResults = new ArrayList<>();
        //查询数据
        /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(null, null,
                    "1hc-avg-zero",
                    deviceCodes,
                    Constant.MonitorInfo.P_0x06B1.getCode(),
                    Constant.MonitorInfo.P_0x06B0.getCode());*/

        return this.DisposeData(queryResults, null, false, false, optDeviceDtos);
    }

    @Override
    public List<CockpitVo> riverwayFlow(CockpitRiverwayAlarmDto dto1) throws ParseException, OpentsdbException {
        List<CockpitVo> list = new ArrayList<>();
        Integer alarmCode = dto1.getAlarmCode();
        Integer renovateState = dto1.getRenovateState();
        if (alarmCode != 2 && renovateState != 2) {
            //起始时间为当天0点时间，结束时间为当前时间
            Date date = new Date();
            Long beginTime = DateUtils.getDayMin(date).getTime();
            Long endTime = date.getTime();
            // 查询设备
            OptDeviceDto optDeviceDto = new OptDeviceDto();
            optDeviceDto.setAreaName(dto1.getAreaName());
            //optDeviceDto.setDeviceType(Constant.EquipmentType.SR500_L_Y0_LDN.getCode());
            List<OptDeviceDto> llAnDanFlowDevice = iOptDeviceService.selectOptDeviceList(optDeviceDto);
            if (llAnDanFlowDevice.size() == 0) {
                return null;
            }
            // 过滤所有设备编码
            String[] deviceCodes = llAnDanFlowDevice.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
            List<QueryResult> queryResults = new ArrayList<>();
            //查询数据
            /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(beginTime, endTime,
                        "1hc-avg-zero",
                        deviceCodes,
                        Constant.MonitorInfo.M_0x0592.getCode());*/

            //判断是否下雨
            RiverwayMonitorDto dto = new RiverwayMonitorDto();
            dto.setState(3);
            dto.setBeginTime(beginTime);
            dto.setEndTime(endTime);
            boolean b = this.selectRainfall(dto);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //处理数据
            for (QueryResult queryResult : queryResults) {
                OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
                CockpitVo vo = new CockpitVo();
                vo.setAlarmType("氨氮一体机");
                vo.setAlarmCode(5);
                vo.setSsAndLs("实时");
                //标记是否报警
                boolean flag = false;
                //处理时间和数据
                LinkedHashMap<Long, Number> dps = queryResult.getDps();
                for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                    Long key = entry.getKey();
                    //如果时间戳为空，则跳过
                    if (key == null) continue;
                    //时间
                    String dateTime = sdf.format(new Date(key * 1000L));
                    //值
                    double v = entry.getValue().doubleValue();
                    //（下雨:值不为0） 或 （晴天:值为0）则跳过 则跳过
                    if ((b && v != 0) || (!b && v == 0)) continue;
                    //有一次报警则结束循环
                    vo.setAlarmDate(dateTime);
                    vo.setDescribe((b ? "天气:雨天;" : "天气:晴天;") + "报警值:" + v + ";");
                    flag = true;
                    break;
                }

                if (flag) {
                    //加入设备信息
                    List<OptDeviceDto> list1 = llAnDanFlowDevice.stream().filter(a -> a.getDeviceCode().equals(opentsdbTags.getSnCode())).collect(Collectors.toList());
                    if (list1.size() > 0) {
                        OptDeviceDto device = list1.get(0);
                        vo.setName(device.getSiteName());
                        vo.setStreet(device.getAreaName());
                    }
                    vo.setZzAndWzz("未整治");
                    list.add(vo);
                }
            }
        }
        return list;
    }

    /**
     * 取的上月液位最大值作为上限，均值作为下限，如果一杆式河道监测站在这个区间内不报警，否则报警
     */
    @Override
    public List<CockpitVo> riverwayLiquidLevel(CockpitRiverwayAlarmDto dto) throws ParseException, OpentsdbException {
        List<CockpitVo> list = new ArrayList<>();
        Integer alarmCode = dto.getAlarmCode();
        Integer renovateState = dto.getRenovateState();
        if (alarmCode != 2 && renovateState != 2) {
            //起始时间为当天0点时间，结束时间为当前时间
            Date date = new Date();
            long beginTime = DateUtils.getDayMin(date).getTime();
            long endTime = date.getTime();
            // 查询设备
            OptDeviceDto optDeviceDto = new OptDeviceDto();
            optDeviceDto.setAreaName(dto.getAreaName());
            optDeviceDto.setDeviceType(Constant.EquipmentType.SE200_L_Y0.getCode());
            List<OptDeviceDto> llAnDanFlowDevice = iOptDeviceService.selectOptDeviceList(optDeviceDto);
            if (llAnDanFlowDevice.size() == 0) {
                return null;
            }
            // 过滤所有设备编码
            String[] deviceCodes = llAnDanFlowDevice.stream().map(OptDeviceDto::getDeviceCode).distinct().toArray(String[]::new);
            List<QueryResult> queryResults = new ArrayList<>();
            //查询数据
            /*List<QueryResult> queryResults = openTSDBUtils.TSDBQuery(beginTime, endTime,
                        "1hc-avg-zero",
                        deviceCodes,
                        Constant.MonitorInfo.M_0x05D1.getCode());*/

            //获取的上月液位的均值
            List<OptDeviceMonitorMonth> lastMonth = optDeviceMonitorMonthService.getBySnCodeLastMonth(deviceCodes);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //处理数据
            for (QueryResult queryResult : queryResults) {
                CockpitVo vo = new CockpitVo();
                vo.setAlarmType("一杆式河道监测站");
                vo.setAlarmCode(4);
                vo.setSsAndLs("实时");
                OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
                String snCode = opentsdbTags.getSnCode();
                double max = 0.00;
                double min = 0.00;
                for (OptDeviceMonitorMonth deviceMonitorMonth : lastMonth) {
                    if (snCode.equals(deviceMonitorMonth.getSnCode())) {
                        String avgValue = deviceMonitorMonth.getAvgValue();
                        max = new BigDecimal(avgValue).multiply(new BigDecimal("1.2")).doubleValue();
                        min = new BigDecimal(avgValue).multiply(new BigDecimal("0.8")).doubleValue();
                        break;
                    }
                }
                //标记是否报警
                boolean flag = false;
                //处理时间和数据
                LinkedHashMap<Long, Number> dps = queryResult.getDps();
                for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                    Long key = entry.getKey();
                    //如果时间戳为空，则跳过
                    if (key == null) continue;
                    //时间
                    String dateTime = sdf.format(new Date(key * 1000L));
                    //值
                    double v = entry.getValue().doubleValue();
                    if (min < v && v < max) continue;
                    //有一次报警则结束循环
                    vo.setAlarmDate(dateTime);
                    vo.setDescribe("下限:" + min + ";" + "上限:" + max + ";" + "报警值:" + v + ";");
                    flag = true;
                    break;
                }

                if (flag) {
                    //加入设备信息
                    List<OptDeviceDto> collect = llAnDanFlowDevice.stream().filter(a -> a.getDeviceCode().equals(snCode)).collect(Collectors.toList());
                    if (collect.size() > 0) {
                        OptDeviceDto device = collect.get(0);
                        vo.setName(device.getSiteName());
                        vo.setStreet(device.getAreaName());
                    }
                    vo.setZzAndWzz("未整治");
                    list.add(vo);
                }
            }
        }
        return list;
    }

    @Override
    public OptDeviceMonitorLastData getBySncodeAndCode(String finalCode, String snCode) {
        LambdaQueryWrapper<OptDeviceMonitorLastData> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OptDeviceMonitorLastData::getDeviceCode, snCode)
                .eq(OptDeviceMonitorLastData::getCode,finalCode);
        return getOne(queryWrapper);
    }
    @Resource
    private ISnCodeRelationService snCodeRelationService;
    @Override
    public List<OptDeviceMonitorLastDataVo> selectOptDeviceMonitorLastDataPage(OptDeviceMonitorLastDataVo optDeviceMonitorLastData) {
        List<OptDeviceMonitorLastDataVo> list =  baseMapper.selectOptDeviceMonitorLastDataPage(optDeviceMonitorLastData);
        list.forEach(optDeviceMonitorLastDataVo -> {
            // 处理24小时雨量
            if("0x0566".equals(optDeviceMonitorLastDataVo.getCode())){
                String snCode = optDeviceMonitorLastDataVo.getDeviceCode();
                SnCodeRelation snCodeRelation = snCodeRelationService.getBySnCode(snCode);
                if(snCodeRelation!=null){
                    // 存在需要映射的snCode
                    String targetCode = snCodeRelation.getSnArea();
                    LambdaQueryWrapper<OptDeviceMonitorLastData> queryWrapper = Wrappers.lambdaQuery();
                    queryWrapper.eq(OptDeviceMonitorLastData::getDeviceCode, targetCode)
                            .eq(OptDeviceMonitorLastData::getCode,"0x0566");
                    OptDeviceMonitorLastData targetData = this.getOne(queryWrapper);
                    if(targetData.getCodeValue() == 0){
                        optDeviceMonitorLastDataVo.setCodeValue(0d);
                    }else{

                        optDeviceMonitorLastDataVo.setCodeValue(BigDecimal.valueOf(targetData.getCodeValue() + snCodeRelation.getChangeData()).setScale(1,BigDecimal.ROUND_HALF_UP).doubleValue());
                    }
                }
            }
        });
        return list;
    }

    /**
     * 数据处理
     *
     * @param queryResults 需处理的数据
     * @param sdf          时间格式
     * @param flag         是否加入最大值和最小值
     * @param flag2        是否加入报警上下限
     * @param dtos         设备信息
     */
    public List<Map<String, Object>> DisposeData(List<QueryResult> queryResults,
                                                 SimpleDateFormat sdf,
                                                 Boolean flag,
                                                 Boolean flag2,
                                                 List<OptDeviceDto> dtos) {
        //判断是否定义时间格式，未传则设置初始格式
        if (sdf == null) sdf = new SimpleDateFormat("yyyy-MM-dd HH");
        //设置保留的数据精度
        DecimalFormat df = new DecimalFormat("#.000");
        List<Map<String, Object>> list = new ArrayList<>();
        for (QueryResult queryResult : queryResults) {
            OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
            Map<String, Object> map = new HashMap<>();
            map.put("tags", opentsdbTags);
            //处理时间和数据
            LinkedHashMap<Long, Number> dps = queryResult.getDps();
            List<String> time = new ArrayList<>();
            List<Number> value = new ArrayList<>();
            List<Double> maxValues = new ArrayList<>();
            List<Double> minValues = new ArrayList<>();
            Double maxValue = 0.000;//标记最大值
            Double minValue = 0.000;//标记最小值
            String timeFlag = null;//根据时间标记重复数据
            double valueFlag = 0.000;//累计数值
            int i = 0;//累计数值的个数
            for (Map.Entry<Long, Number> entry : dps.entrySet()) {
                long key = entry.getKey() == null ? 0L : entry.getKey();
                String timeString = sdf.format(new Date(key * 1000L));
                double v = entry.getValue().doubleValue();
                //第一次，赋值后跳过
                if (timeFlag == null) {
                    timeFlag = timeString;
                    valueFlag = v;
                    maxValue = v;
                    minValue = v;
                    i = 1;
                    continue;
                }
                //时间与上一次相同
                if (timeString.equals(timeFlag)) {
                    valueFlag += v;
                    //获取最大值
                    if (maxValue < v) maxValue = v;
                    //获取最小值
                    if (minValue > v) minValue = v;
                    i++;
                } else {
                    time.add(timeFlag);
                    BigDecimal bigDecimal = new BigDecimal(valueFlag);
                    value.add(bigDecimal.divide(new BigDecimal(i), 3, BigDecimal.ROUND_HALF_UP));//平均数
                    maxValues.add(Double.valueOf(df.format(maxValue)));
                    minValues.add(Double.valueOf(df.format(minValue)));

                    //重置
                    timeFlag = timeString;
                    maxValue = v;
                    minValue = v;
                    valueFlag = v;
                    i = 1;
                }
            }
            //最后一条处理完的数据
            time.add(timeFlag);
            BigDecimal bigDecimal = new BigDecimal(valueFlag);
            value.add(bigDecimal.divide(new BigDecimal(i), 3, BigDecimal.ROUND_HALF_UP));
            maxValues.add(Double.valueOf(df.format(maxValue)));
            minValues.add(Double.valueOf(df.format(minValue)));

            map.put("time", time);
            map.put("value", value);
            //是否加入最大值和最小值
            if (flag) {
                map.put("maxValues", maxValues);
                map.put("minValues", minValues);
            }
            //加入设备信息，未传入设备则进行查询
            String snCode = opentsdbTags.getSnCode();
            OptDeviceDto device = null;
            if (dtos == null) {
                device = iOptDeviceService.getDeviceByCode(snCode);
            } else {
                List<OptDeviceDto> collect = dtos.stream().filter(dto -> dto.getDeviceCode().equals(snCode)).collect(Collectors.toList());
                if (collect.size() > 0) {
                    device = collect.get(0);
                }
            }
            map.put("device", device);
            //加入报警上下限
            if (flag2) {
                OptDeviceMonitorConfig byDeviceCode = optDeviceMonitorConfigService.getByDeviceCode(snCode, opentsdbTags.getMonitorCode());
                if (byDeviceCode != null) {
                    map.put("deviceAlarmUpperLimit", byDeviceCode.getUpperLimit());
                    map.put("deviceAlarmFloorLimit", byDeviceCode.getFloorLimit());
                } else {
                    map.put("deviceAlarmUpperLimit", null);
                    map.put("deviceAlarmFloorLimit", null);
                }
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 处理时间
     */
    private void disposeDate(RiverwayMonitorDto dto) {
        //处理时间参数
        Date beginTimeDate = dto.getBeginTimeDate();
        Date endTimeDate = dto.getEndTimeDate();
        //1.如果起始时间为空，则查询当天0点到目前的数据
        if (beginTimeDate == null) {
            Date date = new Date();
            beginTimeDate = DateUtils.getDayMin(date);
            endTimeDate = date;
        } else {
            //2.如果起始时间不为空，结束时间为空，则查询起始时间那天0点到24点的数据
            if (endTimeDate == null) {
                beginTimeDate = DateUtils.getDayMin(beginTimeDate);
                endTimeDate = DateUtils.getDayMax(beginTimeDate);
            }
        }
        //转为时间戳
        dto.setBeginTime(beginTimeDate.getTime());
        dto.setEndTime(endTimeDate.getTime());
    }

}
